﻿using DotNetty.Buffers;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;

namespace QQ.Codecs
{
    public static class DotNettyByteBufferExtensions
    {
        public enum LengthType
        {
            SHORT, INT, BYTE
        }

        public static IByteBuffer WriteBytesWithLength(this IByteBuffer buffer, IByteBuffer body, LengthType lengthType = LengthType.SHORT, int limitLength = default, int lengthOffset = 0)
        {
            body.ResetReaderIndex();//write the full body
            if (limitLength != default && limitLength < body.ReadableBytes) body.GetBytes(0, body.ResetWriterIndex(), limitLength);
            return (lengthType switch
            {
                LengthType.SHORT => buffer.WriteShort(body.ReadableBytes + lengthOffset),
                LengthType.INT => buffer.WriteInt(body.ReadableBytes + lengthOffset),
                LengthType.BYTE => buffer.WriteByte(body.ReadableBytes + lengthOffset),
                _ => throw new ArgumentException("你输入的LengthType错了。"),
            }).WriteBytes(body);
        }

        public static IByteBuffer ReadBytesWithLength(this IByteBuffer buffer, LengthType lengthType = LengthType.SHORT, int lengthOffset = 0)
            => buffer.ReadBytes(lengthType switch
            {
                LengthType.SHORT => buffer.ReadShort(),
                LengthType.INT => buffer.ReadInt(),
                LengthType.BYTE => buffer.ReadByte(),
                _ => throw new ArgumentException("你输入的LengthType错了。"),
            } + lengthOffset);

        public static byte[] ToArray(this IByteBuffer buffer)
        {
            byte[] ret = new byte[buffer.ResetReaderIndex().ReadableBytes];
            buffer.GetBytes(0, ret);
            return ret;
        }

        public static IByteBuffer ToByteBuffer(this byte[] bytes) => Unpooled.WrappedBuffer(bytes);

        public static string GetString(this IByteBuffer buffer) => buffer.ToString(System.Text.Encoding.UTF8);

        public static IByteBuffer ReadRemaingAndUnzip(this IByteBuffer buffer) => buffer.ReadRemaining().ReadAllAndUnzip();

        public static IByteBuffer ReadAllAndUnzip(this IByteBuffer buffer)
        {
            using MemoryStream stream = new MemoryStream(buffer.ToArray());
            using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
            using MemoryStream output = new MemoryStream();
            deflateStream.CopyTo(output);
            return output.ToArray().ToByteBuffer();
        }

        public static Dictionary<short, IByteBuffer> ReadTLVS(this IByteBuffer buffer)
        {
            Dictionary<short, IByteBuffer> ret = new Dictionary<short, IByteBuffer>();
            short count = buffer.ReadShort();
            for (int i = 0; i < count; i++)
            {
                if (buffer.ReadableBytes < 4) throw new Exception($"读取错误");
                short key = buffer.ReadShort();
                ret[key] = buffer.ReadBytesWithLength(LengthType.SHORT);
            }
            return ret;
        }

        public static IByteBuffer WriteTLVS(this IByteBuffer buffer, Dictionary<short, IByteBuffer> tlvs)
        {
            buffer.WriteShort(tlvs.Count);
            foreach (var item in tlvs) buffer.WriteShort(item.Key).WriteBytesWithLength(item.Value, LengthType.SHORT);
            return buffer;
        }

        public static IByteBuffer ReadRemaining(this IByteBuffer buffer) => buffer.ReadBytes(buffer.ReadableBytes);

        public static byte[] HexStringToBytes(this string hexStr, char spliteChar = ' ') => hexStr.Split(spliteChar).Select(b => Convert.ToByte(b, 16)).ToArray();

        public static IByteBuffer HexStringToByteBuffer(this string hexStr, char spliteChar = ' ') => HexStringToBytes(hexStr, spliteChar).ToByteBuffer();

        public static byte[] ToBytes(this string str) => System.Text.Encoding.Default.GetBytes(str);

        public static IByteBuffer ToByteBuffer(this string str) => str.ToBytes().ToByteBuffer();

        public static string ToHexString(this IByteBuffer buffer) => BitConverter.ToString(buffer.ToArray()).Replace('-', ' ');

        public static byte[] MD5(this byte[] data) => System.Security.Cryptography.MD5.Create().ComputeHash(data);

        public static ByteString ToProtoString(this string str) => ByteString.CopyFromUtf8(str);
    }
}